package com.freeman.boot.auth;

import com.freeman.boot.jwt.JwtTokenUtil;
import com.freeman.boot.jwt.JwtUser;
import com.freeman.boot.user.User;
import com.freeman.boot.user.UserRepository;
import com.taobao.api.ApiException;
import com.taobao.api.TaobaoClient;
import com.taobao.api.domain.BizResult;
import com.taobao.api.request.AlibabaAliqinFcSmsNumSendRequest;
import com.taobao.api.response.AlibabaAliqinFcSmsNumSendResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.Date;
import java.util.concurrent.ThreadLocalRandom;

import static java.util.Arrays.asList;

@Service
public class AuthServiceImpl implements AuthService {
    @Autowired
    private AuthenticationManager authenticationManager;
    @Autowired
    private UserDetailsService userDetailsService;
    @Autowired
    private JwtTokenUtil jwtTokenUtil;
    @Autowired
    private UserRepository userRepository;
    @Autowired
    private TaobaoClient taobaoClient;
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    @Value("${jwt.tokenHead}")
    private String tokenHead;
    @Value("${app.redis.smsKey}")
    private String redisSMSKey;

    @Override
    public User register(User userToAdd) {
        final String username = userToAdd.getUsername();
        if (userRepository.findByUsername(username) != null) {
            return null;
        }

        ValueOperations<String, String> opsForValue = redisTemplate.opsForValue();
        String code = opsForValue.get(getSMSKey(username, "1"));

        if (!userToAdd.getVerifyCode().equals(code)){
            return null;
        }
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        final String rawPassword = userToAdd.getPassword();
        userToAdd.setPassword(encoder.encode(rawPassword));
        userToAdd.setLastPasswordResetDate(new Date());
        userToAdd.setRoles(asList("ROLE_USER"));
        return userRepository.insert(userToAdd);
    }

    @Override
    public String login(String username, String password) {
        UsernamePasswordAuthenticationToken upToken = new UsernamePasswordAuthenticationToken(username, password);
        // Perform the security
        final Authentication authentication = authenticationManager.authenticate(upToken);
        SecurityContextHolder.getContext().setAuthentication(authentication);

        // Reload password post-security so we can generate token
        final UserDetails userDetails = userDetailsService.loadUserByUsername(username);
        return jwtTokenUtil.generateToken(userDetails);
    }

    @Override
    public String refresh(String oldToken) {
        final String token = oldToken.substring(tokenHead.length());
        String username = jwtTokenUtil.getUsernameFromToken(token);
        JwtUser user = (JwtUser) userDetailsService.loadUserByUsername(username);
        if (jwtTokenUtil.canTokenBeRefreshed(token, user.getLastPasswordResetDate())) {
            return jwtTokenUtil.refreshToken(token);
        }
        return null;
    }

    @Override
    public BizResult sendSms(SMS sms) {
        ValueOperations<String, String> opsForValue = redisTemplate.opsForValue();
        String code = opsForValue.get(getSMSKey(sms.getPhone(), sms.getType()));

        if (StringUtils.isEmpty(code)) {
            code = generateCode();
        }

        BizResult bizResult = sendSms(sms.getPhone(), sms.getType(), code);
        if (bizResult.getSuccess()){
            opsForValue.set(getSMSKey(sms.getPhone(), sms.getType()),code);
        }
        return bizResult;
    }

    private BizResult sendSms(String phone, String smsType,String code){
        //TaobaoClient client = new DefaultTaobaoClient("http://gw.api.taobao.com/router/rest", "23709037", "4ae71afdab2d88251f06f11221f0445f");
        AlibabaAliqinFcSmsNumSendRequest req = new AlibabaAliqinFcSmsNumSendRequest();

        req.setExtend("123456");
        req.setSmsType("normal");
        req.setSmsFreeSignName("米饭");
        req.setSmsParamString("{\"code\":\""+code+"\"}");
        //请填写需要接收的手机号码
        req.setRecNum(phone);
        //短信模板id
        req.setSmsTemplateCode("SMS_56735449");

        AlibabaAliqinFcSmsNumSendResponse rsp = null;
        try {
            rsp = taobaoClient.execute(req);
        } catch (ApiException e) {
            //TODO 异常处理
            e.printStackTrace();
        }
        System.out.println(rsp.getResult());
       return  rsp.getResult();
    }

    private String getSMSKey(String phone, String smsType) {
        return this.redisSMSKey + ":" + smsType + ":" + phone;
    }
    /**
    * generate 6 byte code
    *
    * */
    private String generateCode() {
        return "" + ThreadLocalRandom.current().nextInt(10_0000, 100_0000);
    }
}